package qq2564874169.tuaotuao.fx.lock.redis;

import qq2564874169.tuaotuao.fx.FxAutoCloseable;
import qq2564874169.tuaotuao.fx.FxDate;
import qq2564874169.tuaotuao.fx.Task;
import qq2564874169.tuaotuao.fx.lock.AbortTimeoutException;
import qq2564874169.tuaotuao.fx.lock.Lockspace;
import qq2564874169.tuaotuao.fx.lock.LockspaceException;
import qq2564874169.tuaotuao.fx.utils.RandomUtil;
import redis.clients.jedis.JedisPool;

public class RedisLockspace implements Lockspace {
    private JedisPool pool;

    public RedisLockspace(JedisPool pool) {
        this.pool = pool;
    }

    @Override
    public FxAutoCloseable queueLock(String key, Integer abortTimeout) throws AbortTimeoutException {
        if (abortTimeout == null) {
            abortTimeout = Integer.MAX_VALUE;
        }
        long exp = System.currentTimeMillis() + FxDate.SECONDS * abortTimeout.longValue();
        SimpleLocker locker = new SimpleLocker(pool);
        while (locker.lock(key) == false) {
            if (exp < System.currentTimeMillis()) {
                locker.close();
                throw new AbortTimeoutException(key);
            }
            Task.delay(Long.parseLong(RandomUtil.byRange(200, 1000)));
        }
        return locker;
    }

    @Override
    public FxAutoCloseable exLock(String key) throws LockspaceException {
        SimpleLocker locker = new SimpleLocker(pool);
        if (locker.lock(key) == false) {
            locker.close();
            throw new LockspaceException(key + " 已锁定");
        }
        return locker;
    }

    @Override
    public FxAutoCloseable concurrentLock(String key, int max, Integer abortTimeout) throws AbortTimeoutException {
        if (abortTimeout == null) {
            abortTimeout = Integer.MAX_VALUE;
        }
        long exp = System.currentTimeMillis() + FxDate.SECONDS * abortTimeout.longValue();
        ConcurLocker locker = new ConcurLocker(pool);
        while (locker.lock(key, max) == false) {
            if (exp < System.currentTimeMillis()) {
                locker.close();
                throw new AbortTimeoutException(key);
            }
            Task.delay(Long.parseLong(RandomUtil.byRange(200, 1000)));
        }
        return locker;
    }
}
